1 /*
2 * Copyright 2008, The Android Open Source Project
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 <stdlib.h>
18 #include <fcntl.h>
19 #include <errno.h>
20 #include <string.h>
21 #include <dirent.h>
22 #include <sys/socket.h>
23 #include <sys/stat.h>
24 #include <unistd.h>
25 #include <poll.h>
26
27 #include "hardware_legacy/wifi.h"
28 #ifdef LIBWPA_CLIENT_EXISTS
29 #include "libwpa_client/wpa_ctrl.h"
30 #endif
31
32 #define LOG_TAG "WifiHW"
33 #include "cutils/log.h"
34 #include "cutils/memory.h"
35 #include "cutils/misc.h"
36 #include "cutils/properties.h"
37 #include "private/android_filesystem_config.h"
38
39 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
40 #include <sys/_system_properties.h>
41
42 extern int do_dhcp();
43 extern int ifc_init();
44 extern void ifc_close();
45 extern char *dhcp_lasterror();
46 extern void get_dhcp_info();
47 extern int init_module(void *, unsigned long, const char *);
48 extern int delete_module(const char *, unsigned int);
49 void wifi_close_sockets();
50
51 #ifndef LIBWPA_CLIENT_EXISTS
52 #define WPA_EVENT_TERMINATING "CTRL-EVENT-TERMINATING "
53 struct wpa_ctrl {};
wpa_ctrl_cleanup(void)54 void wpa_ctrl_cleanup(void) {}
wpa_ctrl_open(const char * ctrl_path)55 struct wpa_ctrl *wpa_ctrl_open(const char *ctrl_path) { return NULL; }
wpa_ctrl_close(struct wpa_ctrl * ctrl)56 void wpa_ctrl_close(struct wpa_ctrl *ctrl) {}
wpa_ctrl_request(struct wpa_ctrl * ctrl,const char * cmd,size_t cmd_len,char * reply,size_t * reply_len,void (* msg_cb)(char * msg,size_t len))57 int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
58 char *reply, size_t *reply_len, void (*msg_cb)(char *msg, size_t len))
59 { return 0; }
wpa_ctrl_attach(struct wpa_ctrl * ctrl)60 int wpa_ctrl_attach(struct wpa_ctrl *ctrl) { return 0; }
wpa_ctrl_detach(struct wpa_ctrl * ctrl)61 int wpa_ctrl_detach(struct wpa_ctrl *ctrl) { return 0; }
wpa_ctrl_recv(struct wpa_ctrl * ctrl,char * reply,size_t * reply_len)62 int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
63 { return 0; }
wpa_ctrl_get_fd(struct wpa_ctrl * ctrl)64 int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl) { return 0; }
65 #endif
66
67 static struct wpa_ctrl *ctrl_conn;
68 static struct wpa_ctrl *monitor_conn;
69
70 /* socket pair used to exit from a blocking read */
71 static int exit_sockets[2];
72
73 static char primary_iface[PROPERTY_VALUE_MAX];
74 // TODO: use new ANDROID_SOCKET mechanism, once support for multiple
75 // sockets is in
76
77 #ifndef WIFI_DRIVER_MODULE_ARG
78 #define WIFI_DRIVER_MODULE_ARG ""
79 #endif
80 #ifndef WIFI_FIRMWARE_LOADER
81 #define WIFI_FIRMWARE_LOADER ""
82 #endif
83 #define WIFI_TEST_INTERFACE "sta"
84
85 #ifndef WIFI_DRIVER_FW_PATH_STA
86 #define WIFI_DRIVER_FW_PATH_STA NULL
87 #endif
88 #ifndef WIFI_DRIVER_FW_PATH_AP
89 #define WIFI_DRIVER_FW_PATH_AP NULL
90 #endif
91 #ifndef WIFI_DRIVER_FW_PATH_P2P
92 #define WIFI_DRIVER_FW_PATH_P2P NULL
93 #endif
94
95 #ifndef WIFI_DRIVER_FW_PATH_PARAM
96 #define WIFI_DRIVER_FW_PATH_PARAM "/sys/module/wlan/parameters/fwpath"
97 #endif
98
99 #define WIFI_DRIVER_LOADER_DELAY 1000000
100
101 static const char IFACE_DIR[] = "/data/system/wpa_supplicant";
102 #ifdef WIFI_DRIVER_MODULE_PATH
103 static const char DRIVER_MODULE_NAME[] = WIFI_DRIVER_MODULE_NAME;
104 static const char DRIVER_MODULE_TAG[] = WIFI_DRIVER_MODULE_NAME " ";
105 static const char DRIVER_MODULE_PATH[] = WIFI_DRIVER_MODULE_PATH;
106 static const char DRIVER_MODULE_ARG[] = WIFI_DRIVER_MODULE_ARG;
107 #endif
108 static const char FIRMWARE_LOADER[] = WIFI_FIRMWARE_LOADER;
109 static const char DRIVER_PROP_NAME[] = "wlan.driver.status";
110 static const char SUPPLICANT_NAME[] = "wpa_supplicant";
111 static const char SUPP_PROP_NAME[] = "init.svc.wpa_supplicant";
112 static const char P2P_SUPPLICANT_NAME[] = "p2p_supplicant";
113 static const char P2P_PROP_NAME[] = "init.svc.p2p_supplicant";
114 static const char SUPP_CONFIG_TEMPLATE[]= "/system/etc/wifi/wpa_supplicant.conf";
115 static const char SUPP_CONFIG_FILE[] = "/data/misc/wifi/wpa_supplicant.conf";
116 static const char P2P_CONFIG_FILE[] = "/data/misc/wifi/p2p_supplicant.conf";
117 static const char CONTROL_IFACE_PATH[] = "/data/misc/wifi/sockets";
118 static const char MODULE_FILE[] = "/proc/modules";
119
120 static const char IFNAME[] = "IFNAME=";
121 #define IFNAMELEN (sizeof(IFNAME) - 1)
122 static const char WPA_EVENT_IGNORE[] = "CTRL-EVENT-IGNORE ";
123
124 static const char SUPP_ENTROPY_FILE[] = WIFI_ENTROPY_FILE;
125 static unsigned char dummy_key[21] = { 0x02, 0x11, 0xbe, 0x33, 0x43, 0x35,
126 0x68, 0x47, 0x84, 0x99, 0xa9, 0x2b,
127 0x1c, 0xd3, 0xee, 0xff, 0xf1, 0xe2,
128 0xf3, 0xf4, 0xf5 };
129
130 /* Is either SUPPLICANT_NAME or P2P_SUPPLICANT_NAME */
131 static char supplicant_name[PROPERTY_VALUE_MAX];
132 /* Is either SUPP_PROP_NAME or P2P_PROP_NAME */
133 static char supplicant_prop_name[PROPERTY_KEY_MAX];
134
insmod(const char * filename,const char * args)135 static int insmod(const char *filename, const char *args)
136 {
137 void *module;
138 unsigned int size;
139 int ret;
140
141 module = load_file(filename, &size);
142 if (!module)
143 return -1;
144
145 ret = init_module(module, size, args);
146
147 free(module);
148
149 return ret;
150 }
151
rmmod(const char * modname)152 static int rmmod(const char *modname)
153 {
154 int ret = -1;
155 int maxtry = 10;
156
157 while (maxtry-- > 0) {
158 ret = delete_module(modname, O_NONBLOCK | O_EXCL);
159 if (ret < 0 && errno == EAGAIN)
160 usleep(500000);
161 else
162 break;
163 }
164
165 if (ret != 0)
166 ALOGD("Unable to unload driver module \"%s\": %s\n",
167 modname, strerror(errno));
168 return ret;
169 }
170
do_dhcp_request(int * ipaddr,int * gateway,int * mask,int * dns1,int * dns2,int * server,int * lease)171 int do_dhcp_request(int *ipaddr, int *gateway, int *mask,
172 int *dns1, int *dns2, int *server, int *lease) {
173 /* For test driver, always report success */
174 if (strcmp(primary_iface, WIFI_TEST_INTERFACE) == 0)
175 return 0;
176
177 if (ifc_init() < 0)
178 return -1;
179
180 if (do_dhcp(primary_iface) < 0) {
181 ifc_close();
182 return -1;
183 }
184 ifc_close();
185 get_dhcp_info(ipaddr, gateway, mask, dns1, dns2, server, lease);
186 return 0;
187 }
188
get_dhcp_error_string()189 const char *get_dhcp_error_string() {
190 return dhcp_lasterror();
191 }
192
193 #ifdef WIFI_DRIVER_STATE_CTRL_PARAM
wifi_change_driver_state(const char * state)194 int wifi_change_driver_state(const char *state)
195 {
196 int len;
197 int fd;
198 int ret = 0;
199
200 if (!state)
201 return -1;
202 fd = TEMP_FAILURE_RETRY(open(WIFI_DRIVER_STATE_CTRL_PARAM, O_WRONLY));
203 if (fd < 0) {
204 ALOGE("Failed to open driver state control param (%s)", strerror(errno));
205 return -1;
206 }
207 len = strlen(state) + 1;
208 if (TEMP_FAILURE_RETRY(write(fd, state, len)) != len) {
209 ALOGE("Failed to write driver state control param (%s)", strerror(errno));
210 ret = -1;
211 }
212 close(fd);
213 return ret;
214 }
215 #endif
216
is_wifi_driver_loaded()217 int is_wifi_driver_loaded() {
218 char driver_status[PROPERTY_VALUE_MAX];
219 #ifdef WIFI_DRIVER_MODULE_PATH
220 FILE *proc;
221 char line[sizeof(DRIVER_MODULE_TAG)+10];
222 #endif
223
224 if (!property_get(DRIVER_PROP_NAME, driver_status, NULL)
225 || strcmp(driver_status, "ok") != 0) {
226 return 0; /* driver not loaded */
227 }
228 #ifdef WIFI_DRIVER_MODULE_PATH
229 /*
230 * If the property says the driver is loaded, check to
231 * make sure that the property setting isn't just left
232 * over from a previous manual shutdown or a runtime
233 * crash.
234 */
235 if ((proc = fopen(MODULE_FILE, "r")) == NULL) {
236 ALOGW("Could not open %s: %s", MODULE_FILE, strerror(errno));
237 property_set(DRIVER_PROP_NAME, "unloaded");
238 return 0;
239 }
240 while ((fgets(line, sizeof(line), proc)) != NULL) {
241 if (strncmp(line, DRIVER_MODULE_TAG, strlen(DRIVER_MODULE_TAG)) == 0) {
242 fclose(proc);
243 return 1;
244 }
245 }
246 fclose(proc);
247 property_set(DRIVER_PROP_NAME, "unloaded");
248 return 0;
249 #else
250 return 1;
251 #endif
252 }
253
wifi_load_driver()254 int wifi_load_driver()
255 {
256 #ifdef WIFI_DRIVER_MODULE_PATH
257 char driver_status[PROPERTY_VALUE_MAX];
258 int count = 100; /* wait at most 20 seconds for completion */
259
260 if (is_wifi_driver_loaded()) {
261 return 0;
262 }
263
264 if (insmod(DRIVER_MODULE_PATH, DRIVER_MODULE_ARG) < 0)
265 return -1;
266
267 if (strcmp(FIRMWARE_LOADER,"") == 0) {
268 /* usleep(WIFI_DRIVER_LOADER_DELAY); */
269 property_set(DRIVER_PROP_NAME, "ok");
270 }
271 else {
272 property_set("ctl.start", FIRMWARE_LOADER);
273 }
274 sched_yield();
275 while (count-- > 0) {
276 if (property_get(DRIVER_PROP_NAME, driver_status, NULL)) {
277 if (strcmp(driver_status, "ok") == 0)
278 return 0;
279 else if (strcmp(driver_status, "failed") == 0) {
280 wifi_unload_driver();
281 return -1;
282 }
283 }
284 usleep(200000);
285 }
286 property_set(DRIVER_PROP_NAME, "timeout");
287 wifi_unload_driver();
288 return -1;
289 #else
290 #ifdef WIFI_DRIVER_STATE_CTRL_PARAM
291 if (is_wifi_driver_loaded()) {
292 return 0;
293 }
294
295 if (wifi_change_driver_state(WIFI_DRIVER_STATE_ON) < 0)
296 return -1;
297 #endif
298 property_set(DRIVER_PROP_NAME, "ok");
299 return 0;
300 #endif
301 }
302
wifi_unload_driver()303 int wifi_unload_driver()
304 {
305 usleep(200000); /* allow to finish interface down */
306 #ifdef WIFI_DRIVER_MODULE_PATH
307 if (rmmod(DRIVER_MODULE_NAME) == 0) {
308 int count = 20; /* wait at most 10 seconds for completion */
309 while (count-- > 0) {
310 if (!is_wifi_driver_loaded())
311 break;
312 usleep(500000);
313 }
314 usleep(500000); /* allow card removal */
315 if (count) {
316 return 0;
317 }
318 return -1;
319 } else
320 return -1;
321 #else
322 #ifdef WIFI_DRIVER_STATE_CTRL_PARAM
323 if (is_wifi_driver_loaded()) {
324 if (wifi_change_driver_state(WIFI_DRIVER_STATE_OFF) < 0)
325 return -1;
326 }
327 #endif
328 property_set(DRIVER_PROP_NAME, "unloaded");
329 return 0;
330 #endif
331 }
332
ensure_entropy_file_exists()333 int ensure_entropy_file_exists()
334 {
335 int ret;
336 int destfd;
337
338 ret = access(SUPP_ENTROPY_FILE, R_OK|W_OK);
339 if ((ret == 0) || (errno == EACCES)) {
340 if ((ret != 0) &&
341 (chmod(SUPP_ENTROPY_FILE, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) != 0)) {
342 ALOGE("Cannot set RW to \"%s\": %s", SUPP_ENTROPY_FILE, strerror(errno));
343 return -1;
344 }
345 return 0;
346 }
347 destfd = TEMP_FAILURE_RETRY(open(SUPP_ENTROPY_FILE, O_CREAT|O_RDWR, 0660));
348 if (destfd < 0) {
349 ALOGE("Cannot create \"%s\": %s", SUPP_ENTROPY_FILE, strerror(errno));
350 return -1;
351 }
352
353 if (TEMP_FAILURE_RETRY(write(destfd, dummy_key, sizeof(dummy_key))) != sizeof(dummy_key)) {
354 ALOGE("Error writing \"%s\": %s", SUPP_ENTROPY_FILE, strerror(errno));
355 close(destfd);
356 return -1;
357 }
358 close(destfd);
359
360 /* chmod is needed because open() didn't set permisions properly */
361 if (chmod(SUPP_ENTROPY_FILE, 0660) < 0) {
362 ALOGE("Error changing permissions of %s to 0660: %s",
363 SUPP_ENTROPY_FILE, strerror(errno));
364 unlink(SUPP_ENTROPY_FILE);
365 return -1;
366 }
367
368 if (chown(SUPP_ENTROPY_FILE, AID_SYSTEM, AID_WIFI) < 0) {
369 ALOGE("Error changing group ownership of %s to %d: %s",
370 SUPP_ENTROPY_FILE, AID_WIFI, strerror(errno));
371 unlink(SUPP_ENTROPY_FILE);
372 return -1;
373 }
374 return 0;
375 }
376
ensure_config_file_exists(const char * config_file)377 int ensure_config_file_exists(const char *config_file)
378 {
379 char buf[2048];
380 int srcfd, destfd;
381 struct stat sb;
382 int nread;
383 int ret;
384
385 ret = access(config_file, R_OK|W_OK);
386 if ((ret == 0) || (errno == EACCES)) {
387 if ((ret != 0) &&
388 (chmod(config_file, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) != 0)) {
389 ALOGE("Cannot set RW to \"%s\": %s", config_file, strerror(errno));
390 return -1;
391 }
392 return 0;
393 } else if (errno != ENOENT) {
394 ALOGE("Cannot access \"%s\": %s", config_file, strerror(errno));
395 return -1;
396 }
397
398 srcfd = TEMP_FAILURE_RETRY(open(SUPP_CONFIG_TEMPLATE, O_RDONLY));
399 if (srcfd < 0) {
400 ALOGE("Cannot open \"%s\": %s", SUPP_CONFIG_TEMPLATE, strerror(errno));
401 return -1;
402 }
403
404 destfd = TEMP_FAILURE_RETRY(open(config_file, O_CREAT|O_RDWR, 0660));
405 if (destfd < 0) {
406 close(srcfd);
407 ALOGE("Cannot create \"%s\": %s", config_file, strerror(errno));
408 return -1;
409 }
410
411 while ((nread = TEMP_FAILURE_RETRY(read(srcfd, buf, sizeof(buf)))) != 0) {
412 if (nread < 0) {
413 ALOGE("Error reading \"%s\": %s", SUPP_CONFIG_TEMPLATE, strerror(errno));
414 close(srcfd);
415 close(destfd);
416 unlink(config_file);
417 return -1;
418 }
419 TEMP_FAILURE_RETRY(write(destfd, buf, nread));
420 }
421
422 close(destfd);
423 close(srcfd);
424
425 /* chmod is needed because open() didn't set permisions properly */
426 if (chmod(config_file, 0660) < 0) {
427 ALOGE("Error changing permissions of %s to 0660: %s",
428 config_file, strerror(errno));
429 unlink(config_file);
430 return -1;
431 }
432
433 if (chown(config_file, AID_SYSTEM, AID_WIFI) < 0) {
434 ALOGE("Error changing group ownership of %s to %d: %s",
435 config_file, AID_WIFI, strerror(errno));
436 unlink(config_file);
437 return -1;
438 }
439 return 0;
440 }
441
wifi_start_supplicant(int p2p_supported)442 int wifi_start_supplicant(int p2p_supported)
443 {
444 char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
445 int count = 200; /* wait at most 20 seconds for completion */
446 const prop_info *pi;
447 unsigned serial = 0, i;
448
449 if (p2p_supported) {
450 strcpy(supplicant_name, P2P_SUPPLICANT_NAME);
451 strcpy(supplicant_prop_name, P2P_PROP_NAME);
452
453 /* Ensure p2p config file is created */
454 if (ensure_config_file_exists(P2P_CONFIG_FILE) < 0) {
455 ALOGE("Failed to create a p2p config file");
456 return -1;
457 }
458
459 } else {
460 strcpy(supplicant_name, SUPPLICANT_NAME);
461 strcpy(supplicant_prop_name, SUPP_PROP_NAME);
462 }
463
464 /* Check whether already running */
465 if (property_get(supplicant_prop_name, supp_status, NULL)
466 && strcmp(supp_status, "running") == 0) {
467 return 0;
468 }
469
470 /* Before starting the daemon, make sure its config file exists */
471 if (ensure_config_file_exists(SUPP_CONFIG_FILE) < 0) {
472 ALOGE("Wi-Fi will not be enabled");
473 return -1;
474 }
475
476 if (ensure_entropy_file_exists() < 0) {
477 ALOGE("Wi-Fi entropy file was not created");
478 }
479
480 /* Clear out any stale socket files that might be left over. */
481 wpa_ctrl_cleanup();
482
483 /* Reset sockets used for exiting from hung state */
484 exit_sockets[0] = exit_sockets[1] = -1;
485
486 /*
487 * Get a reference to the status property, so we can distinguish
488 * the case where it goes stopped => running => stopped (i.e.,
489 * it start up, but fails right away) from the case in which
490 * it starts in the stopped state and never manages to start
491 * running at all.
492 */
493 pi = __system_property_find(supplicant_prop_name);
494 if (pi != NULL) {
495 serial = __system_property_serial(pi);
496 }
497 property_get("wifi.interface", primary_iface, WIFI_TEST_INTERFACE);
498
499 property_set("ctl.start", supplicant_name);
500 sched_yield();
501
502 while (count-- > 0) {
503 if (pi == NULL) {
504 pi = __system_property_find(supplicant_prop_name);
505 }
506 if (pi != NULL) {
507 /*
508 * property serial updated means that init process is scheduled
509 * after we sched_yield, further property status checking is based on this */
510 if (__system_property_serial(pi) != serial) {
511 __system_property_read(pi, NULL, supp_status);
512 if (strcmp(supp_status, "running") == 0) {
513 return 0;
514 } else if (strcmp(supp_status, "stopped") == 0) {
515 return -1;
516 }
517 }
518 }
519 usleep(100000);
520 }
521 return -1;
522 }
523
wifi_stop_supplicant(int p2p_supported)524 int wifi_stop_supplicant(int p2p_supported)
525 {
526 char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
527 int count = 50; /* wait at most 5 seconds for completion */
528
529 if (p2p_supported) {
530 strcpy(supplicant_name, P2P_SUPPLICANT_NAME);
531 strcpy(supplicant_prop_name, P2P_PROP_NAME);
532 } else {
533 strcpy(supplicant_name, SUPPLICANT_NAME);
534 strcpy(supplicant_prop_name, SUPP_PROP_NAME);
535 }
536
537 /* Check whether supplicant already stopped */
538 if (property_get(supplicant_prop_name, supp_status, NULL)
539 && strcmp(supp_status, "stopped") == 0) {
540 return 0;
541 }
542
543 property_set("ctl.stop", supplicant_name);
544 sched_yield();
545
546 while (count-- > 0) {
547 if (property_get(supplicant_prop_name, supp_status, NULL)) {
548 if (strcmp(supp_status, "stopped") == 0)
549 return 0;
550 }
551 usleep(100000);
552 }
553 ALOGE("Failed to stop supplicant");
554 return -1;
555 }
556
wifi_connect_on_socket_path(const char * path)557 int wifi_connect_on_socket_path(const char *path)
558 {
559 char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
560
561 /* Make sure supplicant is running */
562 if (!property_get(supplicant_prop_name, supp_status, NULL)
563 || strcmp(supp_status, "running") != 0) {
564 ALOGE("Supplicant not running, cannot connect");
565 return -1;
566 }
567
568 ctrl_conn = wpa_ctrl_open(path);
569 if (ctrl_conn == NULL) {
570 ALOGE("Unable to open connection to supplicant on \"%s\": %s",
571 path, strerror(errno));
572 return -1;
573 }
574 monitor_conn = wpa_ctrl_open(path);
575 if (monitor_conn == NULL) {
576 wpa_ctrl_close(ctrl_conn);
577 ctrl_conn = NULL;
578 return -1;
579 }
580 if (wpa_ctrl_attach(monitor_conn) != 0) {
581 wpa_ctrl_close(monitor_conn);
582 wpa_ctrl_close(ctrl_conn);
583 ctrl_conn = monitor_conn = NULL;
584 return -1;
585 }
586
587 if (socketpair(AF_UNIX, SOCK_STREAM, 0, exit_sockets) == -1) {
588 wpa_ctrl_close(monitor_conn);
589 wpa_ctrl_close(ctrl_conn);
590 ctrl_conn = monitor_conn = NULL;
591 return -1;
592 }
593
594 return 0;
595 }
596
597 /* Establishes the control and monitor socket connections on the interface */
wifi_connect_to_supplicant()598 int wifi_connect_to_supplicant()
599 {
600 static char path[PATH_MAX];
601
602 if (access(IFACE_DIR, F_OK) == 0) {
603 snprintf(path, sizeof(path), "%s/%s", IFACE_DIR, primary_iface);
604 } else {
605 snprintf(path, sizeof(path), "@android:wpa_%s", primary_iface);
606 }
607 return wifi_connect_on_socket_path(path);
608 }
609
wifi_send_command(const char * cmd,char * reply,size_t * reply_len)610 int wifi_send_command(const char *cmd, char *reply, size_t *reply_len)
611 {
612 int ret;
613 if (ctrl_conn == NULL) {
614 ALOGV("Not connected to wpa_supplicant - \"%s\" command dropped.\n", cmd);
615 return -1;
616 }
617 ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), reply, reply_len, NULL);
618 if (ret == -2) {
619 ALOGD("'%s' command timed out.\n", cmd);
620 /* unblocks the monitor receive socket for termination */
621 TEMP_FAILURE_RETRY(write(exit_sockets[0], "T", 1));
622 return -2;
623 } else if (ret < 0 || strncmp(reply, "FAIL", 4) == 0) {
624 return -1;
625 }
626 if (strncmp(cmd, "PING", 4) == 0) {
627 reply[*reply_len] = '\0';
628 }
629 return 0;
630 }
631
wifi_supplicant_connection_active()632 int wifi_supplicant_connection_active()
633 {
634 char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
635
636 if (property_get(supplicant_prop_name, supp_status, NULL)) {
637 if (strcmp(supp_status, "stopped") == 0)
638 return -1;
639 }
640
641 return 0;
642 }
643
wifi_ctrl_recv(char * reply,size_t * reply_len)644 int wifi_ctrl_recv(char *reply, size_t *reply_len)
645 {
646 int res;
647 int ctrlfd = wpa_ctrl_get_fd(monitor_conn);
648 struct pollfd rfds[2];
649
650 memset(rfds, 0, 2 * sizeof(struct pollfd));
651 rfds[0].fd = ctrlfd;
652 rfds[0].events |= POLLIN;
653 rfds[1].fd = exit_sockets[1];
654 rfds[1].events |= POLLIN;
655 do {
656 res = TEMP_FAILURE_RETRY(poll(rfds, 2, 30000));
657 if (res < 0) {
658 ALOGE("Error poll = %d", res);
659 return res;
660 } else if (res == 0) {
661 /* timed out, check if supplicant is active
662 * or not ..
663 */
664 res = wifi_supplicant_connection_active();
665 if (res < 0)
666 return -2;
667 }
668 } while (res == 0);
669
670 if (rfds[0].revents & POLLIN) {
671 return wpa_ctrl_recv(monitor_conn, reply, reply_len);
672 }
673
674 /* it is not rfds[0], then it must be rfts[1] (i.e. the exit socket)
675 * or we timed out. In either case, this call has failed ..
676 */
677 return -2;
678 }
679
wifi_wait_on_socket(char * buf,size_t buflen)680 int wifi_wait_on_socket(char *buf, size_t buflen)
681 {
682 size_t nread = buflen - 1;
683 int result;
684 char *match, *match2;
685
686 if (monitor_conn == NULL) {
687 return snprintf(buf, buflen, "IFNAME=%s %s - connection closed",
688 primary_iface, WPA_EVENT_TERMINATING);
689 }
690
691 result = wifi_ctrl_recv(buf, &nread);
692
693 /* Terminate reception on exit socket */
694 if (result == -2) {
695 return snprintf(buf, buflen, "IFNAME=%s %s - connection closed",
696 primary_iface, WPA_EVENT_TERMINATING);
697 }
698
699 if (result < 0) {
700 ALOGD("wifi_ctrl_recv failed: %s\n", strerror(errno));
701 return snprintf(buf, buflen, "IFNAME=%s %s - recv error",
702 primary_iface, WPA_EVENT_TERMINATING);
703 }
704 buf[nread] = '\0';
705 /* Check for EOF on the socket */
706 if (result == 0 && nread == 0) {
707 /* Fabricate an event to pass up */
708 ALOGD("Received EOF on supplicant socket\n");
709 return snprintf(buf, buflen, "IFNAME=%s %s - signal 0 received",
710 primary_iface, WPA_EVENT_TERMINATING);
711 }
712 /*
713 * Events strings are in the format
714 *
715 * IFNAME=iface <N>CTRL-EVENT-XXX
716 * or
717 * <N>CTRL-EVENT-XXX
718 *
719 * where N is the message level in numerical form (0=VERBOSE, 1=DEBUG,
720 * etc.) and XXX is the event name. The level information is not useful
721 * to us, so strip it off.
722 */
723
724 if (strncmp(buf, IFNAME, IFNAMELEN) == 0) {
725 match = strchr(buf, ' ');
726 if (match != NULL) {
727 if (match[1] == '<') {
728 match2 = strchr(match + 2, '>');
729 if (match2 != NULL) {
730 nread -= (match2 - match);
731 memmove(match + 1, match2 + 1, nread - (match - buf) + 1);
732 }
733 }
734 } else {
735 return snprintf(buf, buflen, "%s", WPA_EVENT_IGNORE);
736 }
737 } else if (buf[0] == '<') {
738 match = strchr(buf, '>');
739 if (match != NULL) {
740 nread -= (match + 1 - buf);
741 memmove(buf, match + 1, nread + 1);
742 ALOGV("supplicant generated event without interface - %s\n", buf);
743 }
744 } else {
745 /* let the event go as is! */
746 ALOGW("supplicant generated event without interface and without message level - %s\n", buf);
747 }
748
749 return nread;
750 }
751
wifi_wait_for_event(char * buf,size_t buflen)752 int wifi_wait_for_event(char *buf, size_t buflen)
753 {
754 return wifi_wait_on_socket(buf, buflen);
755 }
756
wifi_close_sockets()757 void wifi_close_sockets()
758 {
759 if (ctrl_conn != NULL) {
760 wpa_ctrl_close(ctrl_conn);
761 ctrl_conn = NULL;
762 }
763
764 if (monitor_conn != NULL) {
765 wpa_ctrl_close(monitor_conn);
766 monitor_conn = NULL;
767 }
768
769 if (exit_sockets[0] >= 0) {
770 close(exit_sockets[0]);
771 exit_sockets[0] = -1;
772 }
773
774 if (exit_sockets[1] >= 0) {
775 close(exit_sockets[1]);
776 exit_sockets[1] = -1;
777 }
778 }
779
wifi_close_supplicant_connection()780 void wifi_close_supplicant_connection()
781 {
782 char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
783 int count = 50; /* wait at most 5 seconds to ensure init has stopped stupplicant */
784
785 wifi_close_sockets();
786
787 while (count-- > 0) {
788 if (property_get(supplicant_prop_name, supp_status, NULL)) {
789 if (strcmp(supp_status, "stopped") == 0)
790 return;
791 }
792 usleep(100000);
793 }
794 }
795
wifi_command(const char * command,char * reply,size_t * reply_len)796 int wifi_command(const char *command, char *reply, size_t *reply_len)
797 {
798 return wifi_send_command(command, reply, reply_len);
799 }
800
wifi_get_fw_path(int fw_type)801 const char *wifi_get_fw_path(int fw_type)
802 {
803 switch (fw_type) {
804 case WIFI_GET_FW_PATH_STA:
805 return WIFI_DRIVER_FW_PATH_STA;
806 case WIFI_GET_FW_PATH_AP:
807 return WIFI_DRIVER_FW_PATH_AP;
808 case WIFI_GET_FW_PATH_P2P:
809 return WIFI_DRIVER_FW_PATH_P2P;
810 }
811 return NULL;
812 }
813
wifi_change_fw_path(const char * fwpath)814 int wifi_change_fw_path(const char *fwpath)
815 {
816 int len;
817 int fd;
818 int ret = 0;
819
820 if (!fwpath)
821 return ret;
822 fd = TEMP_FAILURE_RETRY(open(WIFI_DRIVER_FW_PATH_PARAM, O_WRONLY));
823 if (fd < 0) {
824 ALOGE("Failed to open wlan fw path param (%s)", strerror(errno));
825 return -1;
826 }
827 len = strlen(fwpath) + 1;
828 if (TEMP_FAILURE_RETRY(write(fd, fwpath, len)) != len) {
829 ALOGE("Failed to write wlan fw path param (%s)", strerror(errno));
830 ret = -1;
831 }
832 close(fd);
833 return ret;
834 }
835